//
//  BenchmarkTestConfigViewController.m
//  GCDBenchmark
//
//  Created by Codex on 2025/10/29.
//

#import "BenchmarkTestConfigViewController.h"
#import "BenchmarkTestCase.h"
#import <dispatch/dispatch.h>

typedef NSDictionary<NSString *, id> BenchmarkConfigField;

static NSString * const kFieldTitle = @"title";
static NSString * const kFieldKey = @"key";
static NSString * const kFieldType = @"type";
static NSString * const kFieldOptions = @"options";
static NSString * const kFieldPlaceholder = @"placeholder";
static NSString * const kFieldUnit = @"unit";
static NSString * const kFieldMessage = @"message";
static NSString * const kFieldAllowsZero = @"allowsZero";

@interface BenchmarkTestConfigViewController () <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate>

@property (nonatomic, strong) BenchmarkTestCase *testCase;
@property (nonatomic, strong) NSMutableDictionary<NSString *, id> *workingParams;
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSArray<BenchmarkConfigField *> *fields;
@property (nonatomic, strong) NSArray<NSString *> *playbackFiles;

@end

@implementation BenchmarkTestConfigViewController

- (instancetype)initWithTestCase:(BenchmarkTestCase *)testCase {
    self = [super initWithNibName:nil bundle:nil];
    if (self) {
        _testCase = testCase;
        _workingParams = [testCase.customParams mutableCopy] ?: [NSMutableDictionary dictionary];
        _fields = [self buildFieldsForTestCase:testCase];
        if (testCase.type == BenchmarkTestCaseTypePlayback) {
            _playbackFiles = [[NSBundle mainBundle] pathsForResourcesOfType:@"playback" inDirectory:nil];
        }
        _confirmButtonTitle = @"运行";
        self.title = [NSString stringWithFormat:@"%@ 配置", testCase.name];
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor systemBackgroundColor];

    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消"
                                                                             style:UIBarButtonItemStylePlain
                                                                            target:self
                                                                            action:@selector(cancelTapped)];

    NSString *confirmTitle = self.confirmButtonTitle ?: @"运行";
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:confirmTitle
                                                                              style:UIBarButtonItemStyleProminent
                                                                             target:self
                                                                             action:@selector(runTapped)];

    self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:self.tableView];

    [NSLayoutConstraint activateConstraints:@[
        [self.tableView.topAnchor constraintEqualToAnchor:self.view.topAnchor],
        [self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
        [self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
        [self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
    ]];
}

- (NSArray<BenchmarkConfigField *> *)buildFieldsForTestCase:(BenchmarkTestCase *)testCase {
    NSArray *taskTypeOptions = @[
        @{@"title": @"CPU", @"value": @(0)},
        @{@"title": @"IO", @"value": @(1)},
    ];

    NSArray *qosOptions = @[
        @{@"title": @"Default", @"value": @(QOS_CLASS_DEFAULT)},
        @{@"title": @"Unspecified", @"value": @(QOS_CLASS_UNSPECIFIED)},
    ];

    switch (testCase.type) {
        case BenchmarkTestCaseTypeForkJoin:
            return @[
                [self choiceField:@"任务类型" key:kParamTaskType options:taskTypeOptions],
                [self numberField:@"任务数量" key:kParamTaskCount placeholder:@"512" unit:nil allowZero:NO],
                [self choiceField:@"任务时长" key:kParamTaskDuration options:@[
                    @{@"title": @"10μs", @"value": @(10)},
                    @{@"title": @"100μs", @"value": @(100)},
                    @{@"title": @"1000μs", @"value": @(1000)},
                ]],
                [self choiceField:@"任务 QoS" key:kParamQoS options:qosOptions],
            ];
        case BenchmarkTestCaseTypeFibonacci:
            return @[
                [self choiceField:@"任务类型" key:kParamTaskType options:taskTypeOptions],
                [self numberField:@"递归深度" key:kParamFibDepth placeholder:@"10" unit:nil allowZero:NO],
                [self choiceField:@"任务时长" key:kParamTaskDuration options:@[
                    @{@"title": @"10μs", @"value": @(10)},
                    @{@"title": @"100μs", @"value": @(100)},
                    @{@"title": @"1000μs", @"value": @(1000)},
                ]],
                [self choiceField:@"任务 QoS" key:kParamQoS options:qosOptions],
                [self infoField:@"提示" message:@"深度超过 12 会非常慢，请谨慎选择。"],
            ];
        case BenchmarkTestCaseTypeAriawNSOperation:
        case BenchmarkTestCaseTypeAriawSemaphore:
            return @[
                [self choiceField:@"任务类型" key:kParamTaskType options:taskTypeOptions],
                [self choiceField:@"缓冲区数量" key:kParamBufferCount options:@[
                    @{@"title": @"1", @"value": @(1)},
                    @{@"title": @"4", @"value": @(4)},
                    @{@"title": @"8", @"value": @(8)},
                ]],
                [self numberField:@"Slice 数量" key:kParamSliceCount placeholder:@"512" unit:nil allowZero:NO],
                [self numberField:@"任务时长(μs)" key:kParamTaskDuration placeholder:@"200" unit:@"μs" allowZero:NO],
                [self choiceField:@"任务 QoS" key:kParamQoS options:qosOptions],
            ];
        case BenchmarkTestCaseTypeSerialQueue:
            return @[
                [self choiceField:@"任务类型" key:kParamTaskType options:taskTypeOptions],
                [self numberField:@"任务数量" key:kParamTaskCount placeholder:@"512" unit:nil allowZero:NO],
                [self choiceField:@"任务时长" key:kParamTaskDuration options:@[
                    @{@"title": @"10μs", @"value": @(10)},
                    @{@"title": @"200μs", @"value": @(200)},
                ]],
                [self numberField:@"提交间隔(μs)" key:kParamSubmitInterval placeholder:@"100" unit:@"μs" allowZero:YES],
                [self choiceField:@"任务 QoS" key:kParamQoS options:qosOptions],
            ];
        case BenchmarkTestCaseTypeConcurrentQueue:
            return @[
                [self choiceField:@"任务类型" key:kParamTaskType options:taskTypeOptions],
                [self numberField:@"任务数量" key:kParamTaskCount placeholder:@"512" unit:nil allowZero:NO],
                [self numberField:@"任务时长(μs)" key:kParamTaskDuration placeholder:@"1000" unit:@"μs" allowZero:NO],
                [self choiceField:@"最大并发度" key:kParamMaxConcurrency options:@[
                    @{@"title": @"2", @"value": @(2)},
                    @{@"title": @"4", @"value": @(4)},
                    @{@"title": @"8", @"value": @(8)},
                ]],
                [self numberField:@"提交间隔(μs)" key:kParamSubmitInterval placeholder:@"100" unit:@"μs" allowZero:YES],
                [self choiceField:@"任务 QoS" key:kParamQoS options:qosOptions],
            ];
        case BenchmarkTestCaseTypePeriodicTasks:
            return @[
                [self choiceField:@"任务类型" key:kParamTaskType options:taskTypeOptions],
                [self numberField:@"触发周期(μs)" key:kParamPeriod placeholder:@"10000" unit:@"μs" allowZero:NO],
                [self numberField:@"运行次数" key:kParamTaskCount placeholder:@"100" unit:nil allowZero:NO],
                [self numberField:@"任务时长(μs)" key:kParamTaskDuration placeholder:@"100" unit:@"μs" allowZero:NO],
                [self choiceField:@"任务 QoS" key:kParamQoS options:qosOptions],
            ];
        case BenchmarkTestCaseTypePlayback:
            return @[
                [self playbackField:@"选择 Playback 文件" key:kParamSelectedFileName],
                [self infoField:@"说明" message:@"请选择要回放的 .playback 文件，随后点击右上角运行。"],
            ];
    }
}

- (BenchmarkConfigField *)choiceField:(NSString *)title key:(NSString *)key options:(NSArray<NSDictionary *> *)options {
    return @{
        kFieldTitle: title,
        kFieldKey: key,
        kFieldType: @(BenchmarkTestConfigFieldTypeChoice),
        kFieldOptions: options ?: @[],
    };
}

- (BenchmarkConfigField *)numberField:(NSString *)title
                                   key:(NSString *)key
                            placeholder:(NSString *)placeholder
                                   unit:(NSString * _Nullable)unit
                              allowZero:(BOOL)allowZero {
    NSMutableDictionary *field = [@{
        kFieldTitle: title,
        kFieldKey: key,
        kFieldType: @(BenchmarkTestConfigFieldTypeNumber),
    } mutableCopy];
    if (placeholder) {
        field[kFieldPlaceholder] = placeholder;
    }
    if (unit) {
        field[kFieldUnit] = unit;
    }
    field[kFieldAllowsZero] = @(allowZero);
    return field;
}

- (BenchmarkConfigField *)playbackField:(NSString *)title key:(NSString *)key {
    return @{
        kFieldTitle: title,
        kFieldKey: key,
        kFieldType: @(BenchmarkTestConfigFieldTypePlaybackFile),
    };
}

- (BenchmarkConfigField *)infoField:(NSString *)title message:(NSString *)message {
    return @{
        kFieldTitle: title,
        kFieldType: @(BenchmarkTestConfigFieldTypeInfo),
        kFieldMessage: message ?: @"",
    };
}

#pragma mark - Actions

- (void)cancelTapped {
    if (self.onCancel) {
        self.onCancel();
    } else {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

- (void)runTapped {
    if (![self validateCurrentValues]) {
        return;
    }

    [self.testCase.customParams removeAllObjects];
    [self.testCase.customParams addEntriesFromDictionary:self.workingParams];

    if (self.onConfirm) {
        self.onConfirm(self.testCase);
    } else {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

- (BOOL)validateCurrentValues {
    for (BenchmarkConfigField *field in self.fields) {
        BenchmarkTestConfigFieldType type = [field[kFieldType] integerValue];
        NSString *key = field[kFieldKey];
        if (type == BenchmarkTestConfigFieldTypeNumber || type == BenchmarkTestConfigFieldTypeChoice) {
            NSNumber *value = self.workingParams[key];
            if (!value) {
                NSString *title = field[kFieldTitle] ?: @"参数";
                NSString *message = [NSString stringWithFormat:@"%@ 未设置，请补充后继续。", title];
                [self showAlertWithTitle:@"参数缺失" message:message];
                return NO;
            }
            if (type == BenchmarkTestConfigFieldTypeNumber) {
                BOOL allowZero = [field[kFieldAllowsZero] boolValue];
                if ((!allowZero && value.integerValue <= 0) || (allowZero && value.integerValue < 0)) {
                    NSString *title = field[kFieldTitle] ?: @"参数";
                    NSString *message = [NSString stringWithFormat:@"%@ 取值无效，请重新输入。", title];
                    [self showAlertWithTitle:@"取值无效" message:message];
                    return NO;
                }
            }
        }

        if (type == BenchmarkTestConfigFieldTypePlaybackFile) {
            NSString *fileName = self.workingParams[key];
            if (!fileName || fileName.length == 0) {
                [self showAlertWithTitle:@"未选择文件" message:@"请先选择一个 playback 文件后再运行。"];
                return NO;
            }
        }
    }
    return YES;
}

- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
                                                                   message:message
                                                            preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil]];
    [self presentViewController:alert animated:YES completion:nil];
}

#pragma mark - UITableView DataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.fields.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *identifier = @"ConfigCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
    }

    BenchmarkConfigField *field = self.fields[indexPath.row];
    BenchmarkTestConfigFieldType type = [field[kFieldType] integerValue];
    cell.textLabel.text = field[kFieldTitle];
    cell.textLabel.numberOfLines = 1;
    cell.detailTextLabel.text = [self displayValueForField:field];
    cell.detailTextLabel.textColor = [UIColor secondaryLabelColor];
    cell.selectionStyle = (type == BenchmarkTestConfigFieldTypeInfo) ? UITableViewCellSelectionStyleNone : UITableViewCellSelectionStyleDefault;
    cell.accessoryType = (type == BenchmarkTestConfigFieldTypeInfo) ? UITableViewCellAccessoryNone : UITableViewCellAccessoryDisclosureIndicator;
    cell.detailTextLabel.numberOfLines = 1;

    if (type == BenchmarkTestConfigFieldTypeInfo) {
        cell.detailTextLabel.text = field[kFieldMessage];
        cell.detailTextLabel.textColor = [UIColor tertiaryLabelColor];
        cell.accessoryType = UITableViewCellAccessoryNone;
    }

    return cell;
}

- (NSString *)displayValueForField:(BenchmarkConfigField *)field {
    BenchmarkTestConfigFieldType type = [field[kFieldType] integerValue];
    NSString *key = field[kFieldKey];
    id storedValue = self.workingParams[key];

    switch (type) {
        case BenchmarkTestConfigFieldTypeChoice: {
            NSArray *options = field[kFieldOptions];
            for (NSDictionary *option in options) {
                if ([option[@"value"] isEqual:storedValue]) {
                    return option[@"title"];
                }
            }
            return storedValue ? [storedValue description] : @"未设置";
        }
        case BenchmarkTestConfigFieldTypeNumber: {
            if (!storedValue) {
                return field[kFieldPlaceholder] ?: @"未设置";
            }
            NSString *unit = field[kFieldUnit];
            NSString *base = [storedValue stringValue];
            if (unit.length > 0) {
                return [NSString stringWithFormat:@"%@ %@", base, unit];
            }
            return base;
        }
        case BenchmarkTestConfigFieldTypePlaybackFile:
            if (storedValue && [storedValue length] > 0) {
                return storedValue;
            }
            return @"未选择";
        case BenchmarkTestConfigFieldTypeInfo:
            return field[kFieldMessage] ?: @"";
    }
}

#pragma mark - UITableView Delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    BenchmarkConfigField *field = self.fields[indexPath.row];
    BenchmarkTestConfigFieldType type = [field[kFieldType] integerValue];

    switch (type) {
        case BenchmarkTestConfigFieldTypeChoice:
            [self presentChoiceForField:field];
            break;
        case BenchmarkTestConfigFieldTypeNumber:
            [self presentNumberInputForField:field];
            break;
        case BenchmarkTestConfigFieldTypePlaybackFile:
            [self presentPlaybackPickerForField:field];
            break;
        case BenchmarkTestConfigFieldTypeInfo:
            break;
    }
}

- (void)presentChoiceForField:(BenchmarkConfigField *)field {
    NSString *title = field[kFieldTitle];
    NSArray *options = field[kFieldOptions];
    NSString *key = field[kFieldKey];

    UIAlertController *sheet = [UIAlertController alertControllerWithTitle:title
                                                                   message:nil
                                                            preferredStyle:UIAlertControllerStyleActionSheet];

    for (NSDictionary *option in options) {
        NSString *optionTitle = option[@"title"];
        id value = option[@"value"];
        UIAlertAction *action = [UIAlertAction actionWithTitle:optionTitle
                                                         style:UIAlertActionStyleDefault
                                                       handler:^(UIAlertAction * _Nonnull action) {
            self.workingParams[key] = value;
            [self reloadField:key];
        }];
        [sheet addAction:action];
    }

    [sheet addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];

    if (sheet.popoverPresentationController) {
        sheet.popoverPresentationController.sourceView = self.view;
        sheet.popoverPresentationController.sourceRect = self.view.bounds;
    }

    [self presentViewController:sheet animated:YES completion:nil];
}

- (void)presentNumberInputForField:(BenchmarkConfigField *)field {
    NSString *title = field[kFieldTitle];
    NSString *key = field[kFieldKey];
    NSString *placeholder = field[kFieldPlaceholder];
    NSNumber *currentValue = self.workingParams[key];

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
                                                                   message:@"请输入数值"
                                                            preferredStyle:UIAlertControllerStyleAlert];
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = placeholder;
        textField.keyboardType = UIKeyboardTypeNumberPad;
        if (currentValue) {
            textField.text = [currentValue stringValue];
        }
    }];

    __weak typeof(self) weakSelf = self;
    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
    [alert addAction:[UIAlertAction actionWithTitle:@"确定"
                                              style:UIAlertActionStyleDefault
                                            handler:^(UIAlertAction * _Nonnull action) {
        NSString *text = alert.textFields.firstObject.text;
        NSInteger value = [text integerValue];
        BOOL allowZero = [field[kFieldAllowsZero] boolValue];
        if ((!allowZero && value <= 0) || (allowZero && value < 0)) {
            NSString *error = allowZero ? @"请输入不小于 0 的数值。" : @"请输入大于 0 的数值。";
            [weakSelf showAlertWithTitle:@"取值无效" message:error];
            return;
        }
        weakSelf.workingParams[key] = @(value);
        [weakSelf reloadField:key];
    }]];

    [self presentViewController:alert animated:YES completion:nil];
}

- (void)presentPlaybackPickerForField:(BenchmarkConfigField *)field {
    if (self.playbackFiles.count == 0) {
        [self showAlertWithTitle:@"没有找到 Playback 文件" message:@"请确认工程中包含 .playback 文件。"];
        return;
    }

    NSString *title = field[kFieldTitle];
    NSString *key = field[kFieldKey];

    UIAlertController *sheet = [UIAlertController alertControllerWithTitle:title
                                                                   message:nil
                                                            preferredStyle:UIAlertControllerStyleActionSheet];

    for (NSString *path in self.playbackFiles) {
        NSString *fileName = [path lastPathComponent];
        UIAlertAction *action = [UIAlertAction actionWithTitle:fileName
                                                         style:UIAlertActionStyleDefault
                                                       handler:^(UIAlertAction * _Nonnull action) {
            self.workingParams[key] = fileName;
            [self reloadField:key];
        }];
        [sheet addAction:action];
    }

    [sheet addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];

    if (sheet.popoverPresentationController) {
        sheet.popoverPresentationController.sourceView = self.view;
        sheet.popoverPresentationController.sourceRect = self.view.bounds;
    }

    [self presentViewController:sheet animated:YES completion:nil];
}

- (void)reloadField:(NSString *)key {
    NSUInteger index = [self.fields indexOfObjectPassingTest:^BOOL(BenchmarkConfigField * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        return [obj[kFieldKey] isEqualToString:key];
    }];
    if (index != NSNotFound) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    } else {
        [self.tableView reloadData];
    }
}

@end
